package com.tengju.bff.interfaces.data.settle;

import com.tengju.data.domain.model.alert.AlertEvent;
import com.tengju.data.domain.model.alert.AlertService;
import com.tengju.data.domain.model.report.*;
import com.tengju.data.domain.model.service.AchievementBonusDateConfigService;
import com.tengju.data.domain.shared.CastUtil;
import com.tengju.data.domain.shared.JsonUtil;
import com.tengju.data.domain.shared.Month;
import com.tengju.user.domain.model.user.UserIdCode;
import com.tengju.user.domain.model.user.UserInfo;
import com.tengju.user.domain.model.user.UserInfoRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.time.LocalDate;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author chenhang
 * @Date 2021/1/15
 */
@Component
@Slf4j
@RequiredArgsConstructor(onConstructor_ = {@Autowired})
public class SettleJobListener implements ApplicationListener<SettleEvent> {

    private final AchievementBonusRepository achievementBonusRepository;
    private final AlertService alertService;
    private final UserInfoRepository userInfoRepository;
    private final SettleBonusService settleBonusService;
    private final AchievementBonusDateConfigService configService;

    private final static Integer BATCH_QUERY_LIMIT = 1000;

    @Override
    public void onApplicationEvent(SettleEvent event) {
        Integer month = null;
        try {
            month = CastUtil.castInt(event.getSource());
            if (month == 0) {
                LocalDate today = LocalDate.now();
                //根据配置表查询当天是否入账日期，如果否直接退出
                AchievementBonusDateConfig dateConfig = configService.queryBySettleDate(today);
                if (dateConfig == null) {
                    log.info("月市场补贴入账，{}, 不是入账日期。", today);
                    return;
                }
                if (!dateConfig.canSettle(today)) {
                    log.info("月市场补贴入账, {}, 入账日期不合法,config:{}", today, JsonUtil.toJSONString(dateConfig));
                    throw new AchievementBonusCalException(String.format("月市场补贴入账, %s, 入账日期不合法", today));
                }
                month = CastUtil.castInt(dateConfig.getDataKey());
            }
            settleMonth(month);
            AlertEvent alertEvent = new AlertEvent("月业绩奖励结算任务已完成," + month);
            alertService.alert(alertEvent);
        } catch (Exception e) {
            log.error("月业绩奖励结算任务异常",e);
            AlertEvent alertEvent = new AlertEvent("月业绩奖励结算任务异常");
            alertEvent.addItem("任务参数",month);
            alertEvent.addItem("异常信息",e.getMessage());
            alertService.alert(alertEvent);
        }
    }

    public void settleMonth(Integer month) {
        int count = achievementBonusRepository.countMarketBonusUser(month);
        int offset = 0;
        while (offset <= count) {
            List<Long> idCodes = achievementBonusRepository.listBonusSettleUser(month,offset,BATCH_QUERY_LIMIT);
            if (CollectionUtils.isEmpty(idCodes)) {
                continue;
            }
            doSettleMonth(month,idCodes);
            offset += BATCH_QUERY_LIMIT;
        }
    }

    public void doSettleMonth(Integer month, List<Long> idCodes) {
        if (CollectionUtils.isEmpty(idCodes)) {
            return;
        }
        List<UserBonusResult> userBonusResults = achievementBonusRepository.listAllMarketBonus(
                month,
                AchievementBonusStatusEnum.WAIT_SETTLE,
                idCodes);

        List<UserIdCode> userIdCodes = idCodes.stream().map(UserIdCode::new).collect(Collectors.toList());
        List<UserInfo> userInfos = userInfoRepository.batchGetUserInfo(userIdCodes);
        Map<Long, UserInfo> userInfoMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(userInfos)) {
            userInfoMap = userInfos.stream()
                    .collect(Collectors.toMap(k -> k.getIdCode().getValue(), v -> v, (v1, v2) -> v1));
        }

        Map<Integer,AchievementBonusDateConfig> configMap = new HashMap<>();

        for (UserBonusResult userBonusResult : userBonusResults) {
            try {
                Integer bonusMonthInt = userBonusResult.getMonth();
                AchievementBonusDateConfig config;
                if (configMap.containsKey(bonusMonthInt)) {
                    config = configMap.get(bonusMonthInt);
                } else {
                    Month bonusMonth = new Month(bonusMonthInt);
                    config = configService.queryByDateKeyOrDefault(bonusMonthInt + "",bonusMonth.getRandomDate());
                    configMap.put(bonusMonthInt,config);
                }
                UserInfo userInfo = userInfoMap.get(userBonusResult.getIdCode().getValue());
                settleBonusService.settleAchievementBonus(userBonusResult, userInfo, config);
            } catch (Exception e) {
                log.error("业绩奖励入账失败,idCode:{},profit:{},month:{}",userBonusResult.getIdCode(),userBonusResult.getBonus(),userBonusResult.getMonth(),e);
                AlertEvent alertEvent = new AlertEvent("业绩奖励入账失败:");
                alertEvent.addItem("idCode",userBonusResult.getIdCode());
                alertEvent.addItem("bonus",userBonusResult.getBonus());
                alertEvent.addItem("month",userBonusResult.getMonth());
                alertService.alert(alertEvent);
            }
        }
    }


}
